home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / UUPC11QS.ARJ / MAILSEND.C < prev    next >
C/C++ Source or Header  |  1991-12-07  |  35KB  |  984 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    m a i l s e n d . c                                             */
  3. /*                                                                    */
  4. /*    Subroutines for sending mail for UUPC/extended                  */
  5. /*                                                                    */
  6. /*    Changes copyright 1990, Andrew H. Derbyshire                    */
  7. /*                                                                    */
  8. /*    Change History:                                                 */
  9. /*                                                                    */
  10. /*    15 Sep 90   - Create from maillib.c                         ahd */
  11. /*--------------------------------------------------------------------*/
  12.  
  13. #include <ctype.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #include <process.h>
  20.  
  21. #include "arpadate.h"
  22. #include "expath.h"
  23. #include "lib.h"
  24. #include "hlib.h"
  25. #include "mlib.h"
  26. #include "alias.h"
  27. #include "mail.h"
  28. #include "maillib.h"
  29. #include "mailblib.h"
  30. #include "mailsend.h"
  31. #include "address.h"
  32.  
  33. #define  INDENT "> "
  34.  
  35. /*--------------------------------------------------------------------*/
  36. /*                     Local function prototypes                      */
  37. /*--------------------------------------------------------------------*/
  38.  
  39.  static char *ExplodeAlias(char *header ,
  40.                       const char *alias,
  41.                       FILE *stream,
  42.                       const boolean resent);
  43.  
  44.  
  45.  static void PutHead( const char *label,
  46.                       const char *operand,
  47.                       FILE *stream,
  48.                       const boolean resent);
  49.  
  50.  static boolean Append_Signature(FILE *mailbag,
  51.                      const boolean alternate);
  52.  
  53.  static void Prompt_Input( char *tmailbag,
  54.                           FILE *fmailbag,
  55.                            char *subject,
  56.                           const int current);
  57.  
  58.  static boolean Subcommand( char *buf,
  59.                            FILE *fmailbag,
  60.                            char *tmailbag,
  61.                            char *subject,
  62.                            const int current_msg);
  63.  
  64.  static void CopyOut( const char* input);
  65.  
  66.  static void filter( char *tmailbag, char *command);
  67.  
  68.  static char *GetString( char *input);
  69.  
  70. currentfile();                /* Define current file for panic()     */
  71.  
  72. /*--------------------------------------------------------------------*/
  73. /*    E x p l o d e A l i a s                                         */
  74. /*                                                                    */
  75. /*    Resolves an alias, exploding it into a list if needed.          */
  76. /*--------------------------------------------------------------------*/
  77.  
  78.  static char *ExplodeAlias(char *header ,
  79.                       const char *alias,
  80.                       FILE *stream,
  81.                       const boolean resent)
  82. {
  83.    char *fullname;
  84.    char buffer[LSIZE];
  85.  
  86.    if ((alias == NULL) || (strlen(alias) == 0))
  87.    {
  88.       printmsg(0,"ExplodeAlias: NULL or empty string for argument");
  89.       panic();
  90.    }
  91.  
  92.    fullname = AliasByNick(alias);
  93.  
  94.    printmsg(4,"Processing alias '%s', result '%s'", alias,
  95.       (fullname == NULL) ? alias : fullname);
  96.  
  97.    if (fullname == NULL)            /* No alias found for user?     */
  98.    {                                /* No --> Try node lookup       */
  99.       char user[MAXADDR];
  100.       char node[MAXADDR];
  101.       char path[MAXADDR];
  102.       char bucket[MAXADDR];
  103.  
  104.       ExtractAddress(bucket, (char *) alias, FALSE);
  105.       user_at_node(bucket, path, node, user);
  106.       fullname = AliasByAddr( node, user);
  107.  
  108.       if (fullname == NULL)         /* Did we come up empty?         */
  109.       {
  110.          char *hisuser, *hisnode;
  111.  
  112.          hisuser = strtok( bucket, "@");
  113.          hisnode = strtok( NULL, "@");
  114.          if (equal(hisuser, user ) && (hisnode != NULL) &&
  115.              equal(hisnode, node ) && (strchr( node, '.') == NULL))
  116.          {
  117.             if (equal(hisnode, nodename))
  118.                strcpy(node, domain);
  119.             else {
  120.                strcat(node,".");
  121.                strcat(node,localdomain);
  122.             }
  123.  
  124.             ExtractAddress(path, (char *) alias, TRUE);
  125.             if (strlen( path ) == 0)
  126.                sprintf(buffer,"%s@%s", hisuser, node );
  127.             else
  128.                sprintf(buffer,"\"%s\" <%s@%s>", path, hisuser, node);
  129.             fullname = buffer;
  130.          }
  131.          else
  132.             fullname = (char *) alias; /* Use original information      */
  133.       }
  134.    }
  135.    else {
  136.       ExtractAddress(buffer,fullname,TRUE);
  137.       if (strlen(buffer) == 0)      /* A list of users?              */
  138.       {                             /* Yes --> Do recursive call     */
  139.          char *current = buffer;    /* Current token being processed */
  140.          char *next = NULL;         /* Next token to process         */
  141.  
  142.          strcpy(buffer,fullname);
  143.  
  144.          do {
  145.             current = strtok(current,",\t "); /* Get next alias to process */
  146.             next    = strtok(NULL,"");    /* Also save rest of list        */
  147.             header  = ExplodeAlias( header , current, stream, resent);
  148.                                           /* Get alias, including sub-list */
  149.             current  = next;
  150.          } while ( next != NULL );        /* Until no more tokens exist    */
  151.          return header;                   /* Have written header, return   */
  152.       } /* if */
  153.    }
  154.  
  155.    if (strpbrk(fullname,"!@") == nil(char))
  156.    {
  157.       sprintf(buffer,"%s@%s", fullname ,fdomain);
  158.                               /* Local address                    */
  159.       fullname = buffer;      /* Write out the formatted address  */
  160.    }
  161.  
  162.    PutHead(header, fullname, stream, resent);
  163.                               /* Remote address                   */
  164.    return "";                 /* Make header empty string for
  165.                                  next caller                      */
  166. } /* ExplodeAlias */
  167.  
  168. /*--------------------------------------------------------------------*/
  169. /*    A p p e n d _ S i g n a t u r e                                 */
  170. /*                                                                    */
  171. /*    Append the signature file to the specified mailbag file         */
  172. /*                                                                    */
  173. /*    [Broke this code out from Send_Mail to support the ~a mail      */
  174. /*    subcommand]                                                     */
  175. /*                                                                    */
  176. /*    Returns:  0 on success, 1 if signature file not found           */
  177. /*--------------------------------------------------------------------*/
  178.  
  179. static boolean Append_Signature(FILE *mailbag_fp ,
  180.                      const boolean alternate)
  181. {
  182.    FILE *sigfp;
  183.    char *sig;
  184.    char sigfile[FILENAME_MAX];
  185.    char buf[BUFSIZ];
  186.  
  187.    sig = alternate ? E_altsignature : E_signature;
  188.  
  189.    if(sig != nil(char)) {
  190.       mkfilename(sigfile, homedir, sig);
  191.       printmsg(4, "Append_Signature: signature file %s", sigfile);
  192.       if ((sigfp = FOPEN(sigfile, "r", TEXT)) != nil(FILE)) {
  193.          fputs("-- \n", mailbag_fp);
  194.          while (fgets(buf, BUFSIZ, sigfp) != nil(char))
  195.             fputs(buf, mailbag_fp);
  196.          fclose(sigfp);
  197.          return(0);
  198.       }
  199.       else {
  200.          printmsg(0, "Signature file \"%s\" doesn't exist!\n", sigfile);
  201.          return(1);
  202.       }
  203.    }
  204.    return(0);
  205. }  /* Append_Signature */
  206.  
  207. /*--------------------------------------------------------------------*/
  208. /*    S e n d _ M a i l                                               */
  209. /*                                                                    */
  210. /*    Send text in a mailbag file to address(es) specified by line.   */
  211. /*--------------------------------------------------------------------*/
  212.  
  213. boolean Send_Mail(FILE *datain,
  214.                int argc,
  215.                char *argv[],
  216.                char *subject,
  217.                const boolean resent)
  218. {
  219.    int argx = 0;
  220.    char buf[LSIZE];
  221.    char *header    = "To:";
  222.    char *CcHeader  = "Cc:";
  223.    char *BccHeader = "Bcc:";
  224.    char *pipename  = mktempname(NULL, "TMP");
  225.    FILE *stream = FOPEN(pipename , "w", TEXT);
  226.    int status;
  227.  
  228. /*--------------------------------------------------------------------*/
  229. /*                     Verify our workfile opened                     */
  230. /*--------------------------------------------------------------------*/
  231.  
  232.    if ( stream == NULL )
  233.    {
  234.       printerr(pipename);
  235.       free(pipename);
  236.       return FALSE;
  237.    }
  238.  
  239. /*--------------------------------------------------------------------*/
  240. /*    Add the boilerplate the front:                                  */
  241. /*                                                                    */
  242. /*       Date, From, Organization, and Reply-To                       */
  243. /*--------------------------------------------------------------------*/
  244.  
  245.    PutHead("Date:", arpadate() , stream, resent);
  246.  
  247.    if (bflag[F_BANG])
  248.       sprintf(buf, "(%s) %s!%s", name, fdomain, mailbox );
  249.    else
  250.       sprintf(buf, "\"%s\" <%s@%s>", name, mailbox, fdomain );
  251.    PutHead("From:", buf, stream , resent);
  252.  
  253.    if (organization != NULL )
  254.       PutHead("Organization:", organization, stream, resent );
  255.  
  256.    if (replyto != NULL )
  257.    {
  258.       if (strpbrk(replyto,"!@") == nil(char))
  259.          sprintf(buf,"\"%s\" <%s@%s>", name, replyto , fdomain);
  260.       else
  261.          sprintf(buf,"\"%s\" <%s>", name, replyto);
  262.       PutHead("Reply-To:", buf, stream, resent );
  263.    }
  264.  
  265. /*--------------------------------------------------------------------*/
  266. /*                      Write the addressees out                      */
  267. /*--------------------------------------------------------------------*/
  268.  
  269.    for (argx = 0 ; argx < argc; argx++ )
  270.    {
  271.       if (equal(argv[argx],"-c"))
  272.       {
  273.          header = CcHeader;
  274.          CcHeader = "";
  275.       } /* if */
  276.       else if (equal(argv[argx],"-b"))
  277.       {
  278.          header = BccHeader;
  279.          CcHeader = BccHeader = "";
  280.       } /* if else */
  281.       else
  282.          header = ExplodeAlias( header , argv[argx], stream, resent);
  283.    } /* for */
  284.  
  285. /*--------------------------------------------------------------------*/
  286. /*                  Prompt for carbon copies, if any                  */
  287. /*--------------------------------------------------------------------*/
  288.  
  289.    if ( bflag[F_ASKCC] && Is_Console(stdin) &&
  290.         Console_fgets(buf,LSIZE,"Cc: "))
  291.    {
  292.       char *current = buf;
  293.       header = CcHeader;
  294.       CcHeader = "";
  295.       printmsg(4,"CC buffer: %s",current);
  296.  
  297.       while ((current != NULL) &&
  298.              (current = strtok(current,",\t\n ")) != NULL)
  299.       {
  300.          char *next  =  strtok(NULL,"");
  301.          if (equal(current,"-b"))
  302.          {
  303.             header = BccHeader;
  304.             CcHeader = BccHeader = "";
  305.          } /* if */
  306.          else
  307.             header = ExplodeAlias( header, current, stream, resent);
  308.          current = next;
  309.       } /* while */
  310.    }  /* If Console_fgets() */
  311.  
  312. /*--------------------------------------------------------------------*/
  313. /*                     Handle the subject, if any                     */
  314. /*--------------------------------------------------------------------*/
  315.  
  316.    if (subject != NULL)
  317.       PutHead("Subject:",subject, stream, resent);
  318.    PutHead(NULL, "", stream, resent);  /* Terminate the header file   */
  319.  
  320. /*--------------------------------------------------------------------*/
  321. /*                    Copy the body of the message                    */
  322. /*--------------------------------------------------------------------*/
  323.  
  324.    while (fgets(buf, LSIZE, datain) != nil(char))
  325.    {
  326.       int result = fputs(buf, stream );
  327.       if (result == EOF)
  328.       {
  329.          printerr( pipename );
  330.          panic();
  331.       } /* if */
  332.       if (buf[strlen(buf)-1] != '\n')
  333.             fputc('\n', stream);
  334.    } /* while */
  335.  
  336.    if (!feof(datain))
  337.    {
  338.       printerr("Send_Mail:");
  339.       panic();
  340.    } /* if */
  341.  
  342.    if (datain != stdin)
  343.       fclose(datain);
  344.  
  345. /*--------------------------------------------------------------------*/
  346. /*    Append user's primary signature file, if autosign option on     */
  347. /*--------------------------------------------------------------------*/
  348.  
  349.    if ( bflag[F_AUTOSIGN] )
  350.       Append_Signature(stream, FALSE);
  351.  
  352.    fclose(stream);
  353.  
  354. /*--------------------------------------------------------------------*/
  355. /*                  Invoke the mail delivery program                  */
  356. /*--------------------------------------------------------------------*/
  357.  
  358.    if ( freopen( pipename, "r" , stdin) == NULL )
  359.    {
  360.       printerr(CONSOLE);
  361.       return FALSE;
  362.    }
  363.    else {
  364.       status = spawnlp( P_WAIT, E_rmail,E_rmail, "-t", NULL);
  365.       if ( status < 0 )
  366.       {
  367.          perror( E_rmail );
  368.          printmsg(0,"Unable to execute rmail; mail not delivered.");
  369.       }
  370.       else if ( status > 0 )
  371.          printmsg(0,
  372.             "rmail returned non-zero status; delivery may be incomplete.");
  373.    } /* else */
  374.    freopen( CONSOLE, "r", stdin);
  375.  
  376. /*--------------------------------------------------------------------*/
  377. /*               Log a copy of the mail for the sender                */
  378. /*--------------------------------------------------------------------*/
  379.  
  380.    if (bflag[F_SAVERESENT] || ! resent)
  381.       CopyOut(pipename);
  382.  
  383. /*--------------------------------------------------------------------*/
  384. /*                   Clean up and return to caller                    */
  385. /*--------------------------------------------------------------------*/
  386.  
  387.    remove(pipename);
  388.    free(pipename);
  389.    return (status == 0 );
  390.  
  391. } /*Send_Mail*/
  392.  
  393. /*--------------------------------------------------------------------*/
  394. /*    C o p y O u t                                                   */
  395. /*                                                                    */
  396. /*    Save copy of outgoing mail, if desired                          */
  397. /*--------------------------------------------------------------------*/
  398.  
  399. static void CopyOut( const char* input)
  400. {
  401.    FILE *datain;
  402.    FILE *dataout;
  403.    char buf[BUFSIZ];
  404.    char outbox[FILENAME_MAX];
  405.  
  406.    if (E_filesent == NULL)
  407.       return;
  408.  
  409.    strcpy( outbox, E_filesent);
  410.    expand_path( outbox, homedir, homedir, E_mailext );
  411.  
  412.    datain = FOPEN( input, "r", TEXT);
  413.  
  414.    if (datain == NULL )
  415.    {
  416.       printerr(input);
  417.       panic();
  418.    } /* if */
  419.  
  420.    dataout = FOPEN( outbox, "a", TEXT);
  421.    if (dataout == NULL )
  422.    {
  423.       printerr( outbox );
  424.       panic();
  425.    } /* if */
  426.  
  427.    fputs(MESSAGESEP,dataout);
  428.  
  429.    while (fgets(buf, BUFSIZ, datain) != nil(char))
  430.    {
  431.       int result = fputs(buf, dataout);
  432.       if (result == EOF)
  433.       {
  434.          printerr( outbox );
  435.          panic();
  436.       } /* if */
  437.    } /* while */
  438.  
  439.    if (!feof(datain))
  440.    {
  441.       printerr(input);
  442.       panic();
  443.    } /* if */
  444.  
  445.    fclose(datain);
  446.    fclose(dataout);
  447. } /* CopyOut */
  448.  
  449. /*--------------------------------------------------------------------*/
  450. /* P u t H e a d                                                      */
  451. /*                                                                    */
  452. /* Write one line of an RFC-822 header                                */
  453. /*--------------------------------------------------------------------*/
  454.  
  455.  static void PutHead( const char *label,
  456.                       const char *operand,
  457.                       FILE *stream,
  458.                       const boolean resent)
  459.  {
  460.    static boolean terminate = TRUE;
  461.                               /* If previous line was terminated     */
  462.  
  463.    if (label == NULL )        /* Terminate call?                     */
  464.    {                          /* Yes --> Reset Flag and return       */
  465.       fputc('\n', stream);    /* Terminate the current line          */
  466.       if (!resent)
  467.          fputc('\n', stream); /* Terminate the header file           */
  468.       terminate = TRUE;
  469.       return;
  470.    } /* if */
  471.  
  472.    if (strlen(label))         /* First line of a header?             */
  473.    {
  474.       if (!terminate)         /* Terminate previous line?            */
  475.          fputc('\n', stream);
  476.       if (resent)
  477.          fprintf(stream,"Resent-%s %s",label, operand);
  478.       else
  479.          fprintf(stream,"%-10s %s",label, operand);
  480.       terminate = FALSE;          /* Flag that we did not end file   */
  481.    } /* if */
  482.    else                       /* Continuing line                     */
  483.       fprintf(stream,",\n%-10s %s",label, operand);
  484.  } /* PutHead */
  485.  
  486. /*--------------------------------------------------------------------*/
  487. /*    C o l l e c t _ M a i l                                         */
  488. /*                                                                    */
  489. /*    Create mailbox file for delivery                                */
  490. /*--------------------------------------------------------------------*/
  491.  
  492. boolean Collect_Mail(FILE *stream,
  493.                   int argc,
  494.                   char **argv,
  495.                   const int current_msg,
  496.                   const boolean reply)
  497. {
  498.    boolean editonly = FALSE;
  499.    char Subuffer[LSIZE];
  500.    char *subject = NULL;
  501.    char *tmailbag;
  502.    int  c;                    /* Really a 'char', but who cares?     */
  503.    boolean done = FALSE;
  504.    FILE  *fmailbag;
  505.  
  506.  
  507. /*--------------------------------------------------------------------*/
  508. /*      Determine if we are running interactively; if not, just       */
  509. /*         pass the input stream to Send_Mail for processing          */
  510. /*--------------------------------------------------------------------*/
  511.  
  512.    if (!Is_Console(stream))
  513.    {
  514.       if ( equal(argv[0], "-s" ) )
  515.          return Send_Mail( stream, argc-2, argv+2, argv[1], FALSE);
  516.       else
  517.          return Send_Mail( stream , argc , argv, NULL , FALSE);
  518.    } /* if */
  519.  
  520. /*--------------------------------------------------------------------*/
  521. /*    We are running interactively; create a determine the name of    */
  522. /*                        our work file to be.                        */
  523. /*--------------------------------------------------------------------*/
  524.  
  525.    *Subuffer = '\0';          /* Assume no subject */
  526.    tmailbag = mktempname( NULL, "TXT");
  527.  
  528. /*--------------------------------------------------------------------*/
  529. /*         Determine if we should go straight into the editor         */
  530. /*--------------------------------------------------------------------*/
  531.  
  532.    editonly = bflag[F_AUTOEDIT] && (E_editor != NULL);
  533.  
  534.    if ( equal(argv[0],"-s"))     /* Any subject specified?           */
  535.    {
  536.       strcpy( Subuffer , argv[1] ); /* Save the subject for later    */
  537.       argv += 2;                 /* Skip over it in argument list    */
  538.       argc -= 2;                 /* Giving us fewer args left        */
  539.    }
  540.    else {                        /* No --> Prompt for one            */
  541.       if(Console_fgets(Subuffer,LSIZE,"Subject: "))
  542.       {
  543.          if (Subuffer[strlen(Subuffer) - 1 ] == '\n')
  544.             Subuffer[strlen(Subuffer)-1] = '\0';   /* End the subject */
  545.       }  /* If Console_fgets() */
  546.    } /* if ( equal(argv[0],"-s")) */
  547.  
  548. /*--------------------------------------------------------------------*/
  549. /*      Copy a message from the original input to temporary file      */
  550. /*--------------------------------------------------------------------*/
  551.  
  552.    fmailbag = FOPEN(tmailbag, "w", TEXT);
  553.    if (fmailbag == NULL )
  554.    {
  555.       printerr( tmailbag );
  556.       panic();
  557.    }
  558.  
  559. /*--------------------------------------------------------------------*/
  560. /*               Include incoming message if requested                */
  561. /*--------------------------------------------------------------------*/
  562.  
  563.    if ( bflag[F_AUTOINCLUDE] && reply)
  564.    {
  565.        CopyMsg(current_msg, fmailbag, fromheader , TRUE);
  566.        fprintf(stdout, "Message %d Included\n", current_msg+1);
  567.    } /* if ( bflag[F_AUTOINCLUDE] && reply) */
  568.  
  569. /*--------------------------------------------------------------------*/
  570. /*                     Edit the file if requested                     */
  571. /*--------------------------------------------------------------------*/
  572.  
  573.    if (editonly)              /* Enter editor immediately?     ahd   */
  574.    {                          /* Yes --> Go to it                    */
  575.       fclose(fmailbag);
  576.       Invoke_Editor(E_editor, tmailbag);
  577.    } /* if */
  578.    else {                     /* No  --> prompt for data       ahd   */
  579.       Prompt_Input( tmailbag , fmailbag , Subuffer, current_msg );
  580.       fclose(fmailbag);
  581.    } /*else */
  582.  
  583.  
  584.    do {
  585.       fputs("\nAbort, Continue, Edit, List, or Send? ",stdout);
  586.       c     = Get_One();             /* adaptation for QuickC */  /* pdm */
  587.       switch (tolower( c ))
  588.       {
  589.          case 'c':
  590.             puts("Continue");
  591.             fmailbag = FOPEN(tmailbag, "a", TEXT);
  592.             Prompt_Input( tmailbag , fmailbag , Subuffer, current_msg );
  593.             fclose(fmailbag);
  594.             break;
  595.  
  596.          case 'l':
  597.             puts("List");
  598.             Sub_Pager(tmailbag, islower(c) );
  599.             break;
  600.  
  601.          case 's':
  602.             puts("Send");
  603.             fmailbag = FOPEN(tmailbag, "r", TEXT);
  604.             if (fmailbag == NULL )
  605.             {
  606.                printerr(tmailbag);
  607.                panic();
  608.             }
  609.             if ( strlen( Subuffer ))
  610.                subject = Subuffer;
  611.             Send_Mail(fmailbag, argc, argv, subject, FALSE);
  612.             done = TRUE;
  613.             break;
  614.  
  615.          case 'e':
  616.             puts("Edit");
  617.             Invoke_Editor(E_editor, tmailbag);
  618.             break;
  619.  
  620.          case 'a':
  621.             fputs("Abort\nAre you sure? ", stdout);
  622.             c = Get_One();             /* for QuickC */          /* pdm */
  623.             switch (tolower(c)) {      /* unravel these two calls */
  624.             case 'y':
  625.                puts("Yes");
  626.                done = TRUE;
  627.                break;
  628.             default:
  629.                puts("No");
  630.             } /*switch*/
  631.             break;
  632.  
  633.          default:
  634.             puts("\nEnter A, C, E, L, or S.");
  635.             done = FALSE;
  636.       } /*switch*/
  637.    } while (!done);
  638.  
  639.    remove(tmailbag);
  640.    free(tmailbag);
  641.  
  642.    return TRUE;
  643. } /*Collect_Mail*/
  644.  
  645.  
  646. /*--------------------------------------------------------------------*/
  647. /*    P r o m p t _ I n p u t                                         */
  648. /*                                                                    */
  649. /*    Prompt for mail entry interactively.                            */
  650. /*--------------------------------------------------------------------*/
  651.  
  652. static void Prompt_Input( char *tmailbag,
  653.             FILE *fmailbag,
  654.             char *subject,
  655.             const int current_msg)
  656. {
  657.    char buf[LSIZE];
  658.  
  659.    printf("\nEnter message.  Enter ~? for help.  End input with %s\n",
  660.           bflag[ F_DOT ] ?  "a period (.)" :
  661.          "end-of-file (Control-Z)");
  662.    for ( ; ; )
  663.    {
  664.       if (Console_fgets(buf, LSIZE, "? "))
  665.       {
  666.          if (bflag[F_DOT] && equal(buf,".\n"))
  667.             break;
  668.          else if (Subcommand( buf, fmailbag, tmailbag, subject, current_msg) )
  669.             continue;      /*Don't write line out if subcommand   */
  670.       } /* if */
  671.       else
  672.          break;            /* Exit loop if end of file            */
  673.  
  674.       if (fputs(buf, fmailbag) == EOF )
  675.       {
  676.          printerr( tmailbag );
  677.          panic();
  678.       } /* if (fputs(buf, fmailbag) == EOF ) */
  679.  
  680.       if (buf[strlen(buf)-1] != '\n')
  681.          fputc('\n', fmailbag);
  682.    } /* for */
  683. } /* Prompt_Input */
  684.  
  685. /*--------------------------------------------------------------------*/
  686. /*    S u b c o m m a n d                                             */
  687. /*                                                                    */
  688. /*    Handle tilde (~) subcommands for Interactive mail               */
  689. /*--------------------------------------------------------------------*/
  690.  
  691. static boolean Subcommand( char *buf,
  692.                            FILE *fmailbag,
  693.                            char *tmailbag,
  694.                            char *subject,
  695.                            const int current_msg)
  696. {
  697.    int message;
  698.    char fname[FILENAME_MAX];
  699.    char *token;
  700.    FILE *stream;
  701.  
  702.    if(*buf == '~')        /* Handle mail subcommands  pdm */
  703.    {
  704.       switch(buf[1])
  705.       {
  706. /*--------------------------------------------------------------------*/
  707. /*              Put signature file into current message               */
  708. /*--------------------------------------------------------------------*/
  709.  
  710.          case 'a':
  711.          case 'A':
  712.             Append_Signature(fmailbag, isupper( buf[1] ));
  713.             fputs("(continue)\n", stdout);
  714.             break;
  715.  
  716. /*--------------------------------------------------------------------*/
  717. /*                       Edit outgoing message                        */
  718. /*--------------------------------------------------------------------*/
  719.  
  720.          case 'v':            /* UNIX allows 'v'isual editor         */
  721.          case 'e':
  722.             /* invoke editor with current msg */
  723.             fclose(fmailbag);
  724.             Invoke_Editor(E_editor, tmailbag);
  725.             fmailbag = FOPEN(tmailbag, "a", TEXT);
  726.             fputs("(continue)\n", stdout);
  727.             break;
  728.  
  729. /*--------------------------------------------------------------------*/
  730. /*                 Include any letter in this message                 */
  731. /*--------------------------------------------------------------------*/
  732.  
  733.          case 'i':
  734.          case 'I':
  735.          case 'm':
  736.          case 'M':
  737.             if (fmailbox == NULL)
  738.                puts("Mailbox not accessible!");
  739.             else {
  740.                int *item_list;
  741.                int next_item = PushItemList( &item_list );
  742.                boolean first_pass = TRUE;
  743.  
  744.                token = GetString( &buf[2] );
  745.  
  746.                if (SelectItems( &token, current_msg, LETTER_OP ))
  747.                while( Get_Operand( &message, &token, LETTER_OP, first_pass))
  748.                {
  749.                   CopyMsg( message , fmailbag,
  750.                            islower(buf[1]) ? fromheader : noseperator ,
  751.                            TRUE);
  752.                   fprintf(stdout, "Message %d included\n", message + 1);
  753.                   first_pass = FALSE;
  754.                } /* while */
  755.  
  756.                PopItemList( item_list, next_item );
  757.             } /* else */
  758.             break;
  759.  
  760. /*--------------------------------------------------------------------*/
  761. /*                       Print current message                        */
  762. /*--------------------------------------------------------------------*/
  763.  
  764.          case 'p':
  765.          case 'P':
  766.             fclose(fmailbag);
  767.             Sub_Pager(tmailbag, islower(buf[1]) );
  768.             fmailbag = FOPEN(tmailbag, "a", TEXT);
  769.             fputs("(continue)\n", stdout);
  770.             break;
  771.  
  772. /*--------------------------------------------------------------------*/
  773. /*                           Include a file                           */
  774. /*--------------------------------------------------------------------*/
  775.  
  776.          case 'r':
  777.             token = strtok( &buf[2], " \t\n");
  778.             if ( token == NULL )
  779.             {
  780.                printf("Need a file name for this command!\n");
  781.                break;
  782.             }
  783.             strcpy( fname, token );
  784.             if ( expand_path( fname, NULL, homedir , NULL) == NULL )
  785.                break;
  786.             stream = FOPEN( fname, "r", TEXT);
  787.             if (stream == NULL )
  788.                perror(fname);
  789.             else while( fgets( buf, LSIZE, stream ))
  790.             {
  791.                fputs( buf, fmailbag);
  792.                if ferror( fmailbag )
  793.                {
  794.                   perror( tmailbag);
  795.                   break;
  796.                } /* if */
  797.             } /* else while */
  798.             if (ferror( stream ) )
  799.             {
  800.                perror( fname );
  801.                clearerr( stream );
  802.             } /* if */
  803.             fclose( stream );
  804.             fputs("(continue)\n", stdout);
  805.             break;
  806.  
  807.  
  808. /*--------------------------------------------------------------------*/
  809. /*                        Change mail subject                         */
  810. /*--------------------------------------------------------------------*/
  811.  
  812.          case 's':
  813.             token = GetString( &buf[2] );
  814.             if ( token != NULL )
  815.             {
  816.                strcpy( subject, token );
  817.             }
  818.             else
  819.                printf("No new subject, command ignored\n");
  820.             printf("Subject: %s\n",subject);
  821.             break;
  822.  
  823. /*--------------------------------------------------------------------*/
  824. /*                                Help                                */
  825. /*--------------------------------------------------------------------*/
  826.  
  827.          case '?':
  828.          {
  829.             mkfilename(fname, confdir, "tilde.hlp");
  830.             Sub_Pager( fname, TRUE );
  831.             break;
  832.          }
  833.  
  834. /*--------------------------------------------------------------------*/
  835. /*                             A subshell                             */
  836. /*--------------------------------------------------------------------*/
  837.  
  838.          case '!':
  839.             token = strtok( &buf[2], "\n");
  840.             subshell( token );
  841.             break;
  842.  
  843. /*--------------------------------------------------------------------*/
  844. /*                     Pipe mail through a filter                     */
  845. /*--------------------------------------------------------------------*/
  846.  
  847.          case '|':
  848.             fclose( fmailbag );
  849.             filter( tmailbag, &buf[2] );
  850.             fmailbag = FOPEN(tmailbag, "a", TEXT);
  851.             fputs("(continue)\n", stdout);
  852.             break;
  853.  
  854. /*--------------------------------------------------------------------*/
  855. /*                          Invalid command                           */
  856. /*--------------------------------------------------------------------*/
  857.  
  858.          default:
  859.             fputs("Unknown mail subcommand, ~? for help.\n",
  860.                   stdout);
  861.             break;
  862.       } /* switch */
  863.  
  864.       return TRUE;
  865.    } /* if */
  866.    else
  867.       return FALSE;           /* It wasn't a sub-command             */
  868. } /*SubCommand*/
  869.  
  870. /*--------------------------------------------------------------------*/
  871. /*    f i l t e r                                                     */
  872. /*                                                                    */
  873. /*    Filter the next of an outgoing program into the output mail     */
  874. /*--------------------------------------------------------------------*/
  875.  
  876. static void filter( char *tmailbag, char *command)
  877. {
  878.    char pipename[FILENAME_MAX];
  879.    char *argv[50];
  880.    struct stat statbuf;
  881.    int    argc;
  882.    int    result = 0;
  883.  
  884. /*--------------------------------------------------------------------*/
  885. /*          Break the command to execute down into arguments          */
  886. /*--------------------------------------------------------------------*/
  887.  
  888.    argc = getargs(command, argv);
  889.  
  890.    if ( argc == 0 )
  891.    {
  892.       printf("No filter name given!\n");
  893.       return;
  894.    }
  895.    argv[argc] = NULL;
  896.  
  897. /*--------------------------------------------------------------------*/
  898. /*   Set up our standard input and standard output for the command    */
  899. /*--------------------------------------------------------------------*/
  900.  
  901.    mktempname(pipename, "TXT");
  902.  
  903.    if ( freopen(tmailbag, "r", stdin) == NULL )
  904.       printerr( tmailbag );
  905.    else if (freopen(pipename, "w", stdout) == NULL )
  906.    {
  907.       printerr( pipename );
  908.       freopen("con", "r", stdin);
  909.    }
  910. /*--------------------------------------------------------------------*/
  911. /*                          Run the command                           */
  912. /*--------------------------------------------------------------------*/
  913.    else {
  914.       result = spawnvp( P_WAIT, argv[0], argv );
  915.       freopen("con", "w", stdout);
  916.       setbuf(stdout, NULL );
  917.       freopen("con", "r", stdin);
  918.       setbuf(stdin, NULL );
  919.  
  920.       if (result == -1)       /* Did spawn fail?            */
  921.          printerr(argv[0]);   /* Yes --> Report error       */
  922.       else if( stat( pipename, &statbuf) <0 )   /* Create output?    */
  923.       {
  924.          printf(0,"Cannot determine status of output %s",pipename);
  925.          printerr( pipename );
  926.       }
  927.       else if( statbuf.st_size == 0 )  /* Anything in the file?      */
  928.          printf("Outfile file is empty!\n");
  929.       else {                  /* Good output, replace input file     */
  930.          remove( tmailbag );
  931.          if (rename( pipename, tmailbag ))
  932.             printerr( pipename );
  933.       } /* else */
  934.    } /* else */
  935.  
  936. /*--------------------------------------------------------------------*/
  937. /*                   Clean up and return to caller                    */
  938. /*--------------------------------------------------------------------*/
  939.  
  940.    remove( pipename );
  941.  
  942. } /* filter */
  943.  
  944. /*--------------------------------------------------------------------*/
  945. /*    G e t S t r i n g                                               */
  946. /*                                                                    */
  947. /*    Get non-whitespace in a string                                  */
  948. /*--------------------------------------------------------------------*/
  949.  
  950. static char *GetString( char *input)
  951. {
  952.    char *end;
  953.  
  954. /*--------------------------------------------------------------------*/
  955. /*                   Look for first data in string                    */
  956. /*--------------------------------------------------------------------*/
  957.  
  958.    while( isspace( *input ))
  959.       input++ ;
  960.  
  961. /*--------------------------------------------------------------------*/
  962. /*   If no input or all blanks, return NULL to denote empty string    */
  963. /*--------------------------------------------------------------------*/
  964.  
  965.    if (*input == '\0')
  966.       return NULL ;
  967.  
  968. /*--------------------------------------------------------------------*/
  969. /*                Delete whitespace from end of string                */
  970. /*--------------------------------------------------------------------*/
  971.  
  972.    end = &input[ strlen( input ) - 1 ];
  973.  
  974.    while (isspace(*end))
  975.       *end-- = '\0';
  976.  
  977. /*--------------------------------------------------------------------*/
  978. /*                 Return beginning of string to caller               */
  979. /*--------------------------------------------------------------------*/
  980.  
  981.    return input;
  982.  
  983. } /* GetString */
  984.